package parsing

import (
	"fmt"
	"log"
	"mini-sql/config"
	"mini-sql/model"
	"mini-sql/parser"
	"mini-sql/utils"
	"reflect"
	"strconv"
	"strings"

	"github.com/antlr4-go/antlr/v4"
)

var (
	symbolTypeMap = map[int]model.ExprType{
		parser.SQLiteLexerAND_:    model.ExprTypeAnd,      // AND
		parser.SQLiteLexerOR_:     model.ExprTypeOr,       // OR
		parser.SQLiteLexerASSIGN:  model.ExprTypeCmpEq,    // =
		parser.SQLiteLexerEQ:      model.ExprTypeCmpEq,    // ==
		parser.SQLiteLexerNOT_EQ1: model.ExprTypeCmpNotEq, // !=
		parser.SQLiteLexerNOT_EQ2: model.ExprTypeCmpNotEq, // <>
		parser.SQLiteLexerGT:      model.ExprTypeCmpGt,    // >
		parser.SQLiteLexerGT_EQ:   model.ExprTypeCmpGtEq,  // >=
		parser.SQLiteLexerLT:      model.ExprTypeCmpLt,    // <
		parser.SQLiteLexerLT_EQ:   model.ExprTypeCmpLtEq,  // <=
	}
)

func panicf(msg string, params ...interface{}) {
	panic(fmt.Errorf(msg, params...))
}

func assertChildCount(expected int, tree antlr.Tree) {
	actual := tree.GetChildCount()
	if actual != expected {
		panic(fmt.Sprintf("expect %v children but got %v, type=%v", expected, actual, reflect.TypeOf(tree)))
	}
}

func ConvertToAstTree(tree parser.IParseContext) []*model.QueryStatement {
	if tree == nil {
		return nil
	}

	result := make([]*model.QueryStatement, 0)
	for _, child := range tree.GetChildren() {
		stmtList, ok := child.(parser.ISql_stmt_listContext)
		if ok {
			queryStatementList := convertStatmentList(stmtList)
			result = append(result, queryStatementList...)
		}
	}
	return result
}

func convertStatmentList(stmtList parser.ISql_stmt_listContext) []*model.QueryStatement {
	result := make([]*model.QueryStatement, 0)
	for _, child := range stmtList.AllSql_stmt() {
		result = append(result, convertStatement(child))
	}
	return result
}

func convertStatement(tree antlr.Tree) *model.QueryStatement {
	if config.DebugParsing {
		log.Printf("Statement: type=%v, childCount=%v", reflect.TypeOf(tree), tree.GetChildCount())
	}

	insertStatement, ok := tree.(parser.IInsert_stmtContext)
	if ok {
		return convertInsertStatement(insertStatement)
	}

	selectStatement, ok := tree.(parser.ISelect_stmtContext)
	if ok {
		return convertSelectStatement(selectStatement)
	}

	updateStatement, ok := tree.(parser.IUpdate_stmtContext)
	if ok {
		return convertUpdateStatement(updateStatement)
	}

	deleteStatement, ok := tree.(parser.IDelete_stmtContext)
	if ok {
		return convertDeleteStatement(deleteStatement)
	}

	sqlStatement, ok := tree.(parser.ISql_stmtContext)
	if ok {
		assertChildCount(1, sqlStatement)
		return convertStatement(sqlStatement.GetChild(0))
	}

	panicf("unknown statement %v", reflect.TypeOf(tree))
	return nil
}

func convertDeleteStatement(deleteStatement parser.IDelete_stmtContext) *model.QueryStatement {
	deleteStmt := model.DeleteStatement{}
	deleteStmt.TableRef = convertExpr(deleteStatement.Qualified_table_name())
	deleteStmt.WhereClause = convertExpr(deleteStatement.GetWhereExpr())

	return &model.QueryStatement{
		DeleteStatement: &deleteStmt,
	}
}

func convertUpdateStatement(updateStatement parser.IUpdate_stmtContext) *model.QueryStatement {
	updateStmt := model.UpdateStatement{}
	updateStmt.TableRef = convertExpr(updateStatement.Qualified_table_name())
	updateStmt.AssignList = convertAssignExprList(updateStatement.Assign_expr_list())
	updateStmt.WhereClause = convertExpr(updateStatement.GetWhereExpr())

	return &model.QueryStatement{
		UpdateStatement: &updateStmt,
	}
}

func convertAssignExprList(iAssignExprListContext parser.IAssign_expr_listContext) []model.AssignExpr {
	names := iAssignExprListContext.AllColumn_name()
	exprList := iAssignExprListContext.AllExpr()
	if len(names) != len(exprList) {
		utils.Panicf("assignExpr length not match")
	}
	result := make([]model.AssignExpr, 0)
	for index, name := range names {
		value := convertExpr(exprList[index])
		result = append(result, model.AssignExpr{
			Name:  convertExpr(name).StrValue,
			Value: value,
		})
	}
	return result
}

func convertSelectStatement(selectStatement parser.ISelect_stmtContext) *model.QueryStatement {
	for _, child := range selectStatement.AllSelect_core() {
		return convertSelectCore(child)
	}
	panicf("expect select statement")
	return nil
}

func convertSelectCore(selectCore parser.ISelect_coreContext) *model.QueryStatement {
	result := model.NewSelectStatement()

	result.ColumnNames = convertResultColumnList(selectCore.Result_column_list())
	fromList := convertTableOrSubQueryList(selectCore.AllTable_or_subquery())
	result.FromClause = &model.Expr{
		ExprType: model.ExprTypeNameIdList,
		Children: fromList,
	}
	result.WhereClause = convertExpr(selectCore.GetWhereExpr())

	// todo 其他条件

	return &model.QueryStatement{
		SelectStatement: result,
	}
}

func convertResultColumnList(columnList parser.IResult_column_listContext) []*model.Expr {
	result := make([]*model.Expr, 0)
	for _, child := range columnList.AllResult_column() {
		result = append(result, convertExpr(child))
	}
	return result
}

func convertTableOrSubQueryList(exprList []parser.ITable_or_subqueryContext) []*model.Expr {
	result := make([]*model.Expr, 0)
	for _, child := range exprList {
		result = append(result, convertExpr(child))
	}
	return result
}

func convertInsertStatement(insertStatement parser.IInsert_stmtContext) *model.QueryStatement {
	insert_ := &model.InsertStatement{}
	result := model.QueryStatement{
		InsertStatement: insert_,
	}

	insert_.TableRef = convertExpr(insertStatement.Table_name())
	insert_.ValueRowList = convertValueRowList(insertStatement.Values_clause())
	insert_.Fields = convertColumnNameList(insertStatement.AllColumn_name())
	return &result
}

func convertColumnNameList(columnNameList []parser.IColumn_nameContext) []*model.Expr {
	result := make([]*model.Expr, 0)
	for _, child := range columnNameList {
		result = append(result, convertExpr(child))
	}
	return result
}

func convertExpr(tree antlr.Tree) *model.Expr {
	if tree == nil {
		return nil
	}

	if config.DebugParsing {
		log.Printf("Expr: type=%v, childCount=%v", reflect.TypeOf(tree), tree.GetChildCount())
	}

	// 原子结构
	terminalNode, ok := tree.(*antlr.TerminalNodeImpl)
	if ok {
		if config.DebugParsing {
			log.Printf("terminal.symbol=%v, text=%v", terminalNode.GetSymbol(), terminalNode.GetText())
		}

		return convertTerminal(terminalNode)
	}

	// 组合结构
	if tree.GetChildCount() == 0 {
		panic(fmt.Sprintf("expect tree.ChildCount>0, type=%v", reflect.TypeOf(tree)))
	}

	// 表达式结构
	if tree.GetChildCount() == 3 {
		return convertExprOperator(tree)
	}

	// 单层嵌套结构
	child := tree.GetChild(0)
	return convertExpr(child)
}

func convertTerminal(terminalNode *antlr.TerminalNodeImpl) *model.Expr {
	token := terminalNode.GetSymbol()
	switch token.GetTokenType() {
	case parser.SQLiteLexerCOMMA:
		return &model.Expr{
			ExprType: model.ExprTypeComma,
			StrValue: terminalNode.String(),
		}
	case parser.SQLiteLexerSTAR:
		return &model.Expr{
			ExprType: model.ExprTypeStar,
			StrValue: "*",
		}
	case parser.SQLiteLexerSTRING_LITERAL:
		return &model.Expr{
			ExprType: model.ExprTypeStr,
			StrValue: convertStringLiteral(terminalNode.String()),
		}
	case parser.SQLiteLexerIDENTIFIER:
		return &model.Expr{
			ExprType: model.ExprTypeNameId,
			StrValue: convertNameId(terminalNode.String()),
		}
	case parser.SQLiteLexerNUMERIC_LITERAL:
		numValue := terminalNode.String()
		if strings.Contains(numValue, ".") {
			floatValue, err := strconv.ParseFloat(numValue, 64)
			if err != nil {
				utils.Panicf("ParseFloat failed, value: %v, err:%v", numValue, err)
			}

			return &model.Expr{
				ExprType:   model.ExprTypeFloat,
				FloatValue: floatValue,
			}
		} else {
			intValue, err := strconv.ParseInt(numValue, 10, 64)
			if err != nil {
				utils.Panicf("ParseInt failed, value: %v, err:%v", numValue, err)
			}
			return &model.Expr{
				ExprType: model.ExprTypeInt64,
				IntValue: intValue,
			}
		}
	}
	if config.DebugParsing {
		log.Printf("unknown tokenType %v", token.GetTokenType())
	}
	return &model.Expr{
		StrValue: terminalNode.String(),
	}
}

func convertNameId(s string) string {
	if len(s) == 0 {
		utils.Panicf("nameId is empty")
	}
	if s[0] == '`' || s[0] == '[' || s[0] == '"' {
		// 三种quote方式
		return s[1 : len(s)-1]
	}
	return s
}

// convertValueRowList
// eg: ("name", 1), ("name-2", 20)
func convertValueRowList(valueList parser.IValues_clauseContext) []*model.ValueRow {
	result := make([]*model.ValueRow, 0)

	for _, child := range valueList.GetChildren() {
		values, ok := child.(parser.IValue_rowContext)
		if ok {
			row := convertValueRow(values)
			result = append(result, row)
		}
	}
	return result
}

// convertValues
// eg: ("name", 1)
func convertValueRow(values parser.IValue_rowContext) *model.ValueRow {
	exprList := make([]*model.Expr, 0)
	for _, child := range values.AllExpr() {
		exprList = append(exprList, convertExpr(child))
	}
	return &model.ValueRow{
		Tuple: exprList,
	}
}

func convertStringLiteral(s string) string {
	// todo 转换字符串转义
	return s[1 : len(s)-1]
}

func convertExprOperator(operatorExpr antlr.Tree) *model.Expr {
	assertChildCount(3, operatorExpr)
	first := convertExpr(operatorExpr.GetChild(0))
	opChild := operatorExpr.GetChild(1)
	second := convertExpr(operatorExpr.GetChild(2))
	return &model.Expr{
		ExprType: getOperatorType(opChild),
		Children: []*model.Expr{
			first,
			second,
		},
	}
}

func getOperatorType(tree antlr.Tree) model.ExprType {
	terminalNode, ok := tree.(*antlr.TerminalNodeImpl)
	if !ok {
		utils.Panicf("getOperatorType: expect terminalNode but got %v", reflect.TypeOf(tree))
	}
	result := symbolTypeMap[terminalNode.GetSymbol().GetTokenType()]
	if result == 0 {
		utils.Panicf("getOperatorType: unsupported token %v", terminalNode.GetSymbol())
	}
	return result
}
